﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

using NUnitResults;

namespace CheckNUnitResults
{
    /// <summary>
    /// Checks a results file for test status, and returns 0 if the tests passed,
    /// or another positive number for a different test status. A negative return value
    /// indicates an error.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Executes the program.
        /// </summary>
        /// <param name="args">Should contain a single argument - the file to check.</param>
        /// <returns>A 0 if the tests succeeded.
        /// A positive number if the tests were checked, but did not succeed.
        /// A negative number if the program encountered an error.</returns>
        static Int32 Main(string[] args)
        {
            Console.WriteLine();

            if (args.Length != 1)
            {
                PrintUsage();
                return -1;
            }

            var file = args[0];
            Status status;

            try
            {
                status = GetResultFileStatus(file);
            }
            catch (Exception ex)
            {
                Console.WriteLine("An exception occurred whilst reading test results:");
                Console.WriteLine(ex);
                return -2;
            }

            var returnCode = GetReturnCode(status);

            if (!returnCode.HasValue)
            {
                Console.WriteLine("Unable to determine return code for status {0}", status);
                return -3;
            }

            return returnCode.Value;
        }

        /// <summary>
        /// Gets the return code for a given status.
        /// </summary>
        /// <param name="status"></param>
        /// <returns></returns>
        private static Nullable<Int32> GetReturnCode(Status status)
        {
            var returnCodes = new Dictionary<Status, Int32>
            {
                { Status.Success, 0 },
                { Status.Ignored, 1 },
                { Status.Failed, 2 },
                { Status.Error, 3 },
                { Status.Inconclusive, 4 }
            };

            var returnCode = 0;

            if (!returnCodes.TryGetValue(status, out returnCode))
            {
                return null;
            }

            return returnCode;
        }

        /// <summary>
        /// Gets the status of the tests in the specified results file.
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        private static Status GetResultFileStatus(String file)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            var resultFile = new ResultFile(new FileStreamProvider(file));
            return resultFile.ReadTestResults()
                                .Select(t => t.Status)
                                .OrderBy(s => s)
                                .FirstOrDefault();
        }

        /// <summary>
        /// Prints the usage for this exe.
        /// </summary>
        private static void PrintUsage()
        {
            Console.WriteLine("Usage:");
            Console.WriteLine();
            Console.WriteLine("    CheckNUnitResults.exe resultsFilePath");
            Console.WriteLine();
        }
    }
}
